﻿using System;
using System.Linq;
using System.Net;
using System.Xml.Linq;
using System.Windows.Media;
using System.Globalization;
using System.Collections.Generic;

using Colorful.Control.Properties;
using System.Xml;


namespace Colorful.Control.Services
{
    public class ColourLovers : IGetColors
    {
        private const string apiBaseUrl = "http://www.colourlovers.com/api/";

        private static IWebProxy Proxy
        {
            get
            {
                if (Settings.Default.UseDefaultProxy)
                    return WebRequest.DefaultWebProxy;

                if (string.IsNullOrEmpty(Settings.Default.ProxyAddress))
                    return null;

                return new WebProxy(Settings.Default.ProxyAddress, false, new string[0], CredentialCache.DefaultNetworkCredentials);
            }
        }

        public System.Drawing.Bitmap Logo
        { 
            get { return Resources.ColourLovers36; }
        }

        public string LogoTooltip { get { return "Colored by ColourLovers"; } }

        public IEnumerable<ColorList> SupportedLists
        {
            get
            {
                yield return ColorList.Recent;
                yield return ColorList.Popular;
                yield return ColorList.Random;                                
                yield return ColorList.Search;
            }
        }

        public List<Palette> Search(string searchQuery, int startIndex, int itemsPerPage, out int totalItems)
        {
            string requestUrl = string.Format("{0}/palettes?format=xml&resultOffset={1}&numResults={2}&keywords={3}", apiBaseUrl, startIndex * itemsPerPage, itemsPerPage, searchQuery);
            return DownloadColors( requestUrl, out totalItems ); 
        }

   
        /*
            Args: 
                lover	=	COLOURlover
                hueOption	=	yellow,orange,red  or  green,violet  or  blue
                [Possible Values can be a combination of: red, orange, yellow, green, aqua, blue, violet, and / or fuchsia]
                hex	=	00FF33   [Possible Values: any valid 6-char hex value]
                keywords	=	search+term
                keywordExact	=	0 or 1   [Perform an exact search for the keywords passed. Default 0]
                orderCol	=	X   [Where X can be: dateCreated, score, name, numVotes, or numViews]
                sortBy	=	X   [Where X can be: ASC or DESC. Default ASC]
                numResults	=	20   [Number of results to return, maximum of 100. Default 20]
                resultOffset	=	5   [Result offset, for paging. Default 0]
                format	=	json or xml   [Result format. Default is xml]
         */

        /*
             Stats API:
                baseurl + /stats/palettes
         */

        public List<Palette> GetColors(ColorList list, int startIndex, int itemsPerPage, out int totalItems)
        {
            string requestUrl = string.Format("{0}/palettes/{1}?format=xml&resultOffset={2}&numResults={3}", apiBaseUrl, GetListName(list), startIndex * itemsPerPage, itemsPerPage);
            return DownloadColors( requestUrl, out totalItems ); 
        }

        /// <summary>Gets an <see cref="XmlReader"/> for the given <paramref name="url"/>, 
        /// using the static <see cref="IWebProxy"/> instance - <see cref="Proxy"/>.</summary>
        /// <param name="url">The Url to read.</param>
        /// <returns>An instance of an <see cref="XmlReader"/> with the given <paramref name="url"/> and proxy.</returns>
        private static XmlReader GetProxyXmlReader(string url)
        {
            var request = WebRequest.Create( url );
            request.Proxy = Proxy;

            var response = (HttpWebResponse) request.GetResponse();
            return XmlReader.Create( response.GetResponseStream() );
        }

        private List<Palette> DownloadColors(string requestUrl, out int recordCount)
        {
            //The only way to get the total stats for Colourlovers is via a seperate API call...
            using(XmlReader reader = GetProxyXmlReader( apiBaseUrl + "/stats/palettes" ))
            {
                var document = XElement.Load( reader );
                Int32.TryParse( document.Element( "total" ).Value, out recordCount );
            }

            using (XmlReader reader = GetProxyXmlReader(requestUrl))
            {
                var document = XElement.Load( reader );

                var query = from theme in document.Elements( "palette" )
                            select new Palette
                                       {
                                           Name = theme.Element( "title" ).Value,
                                           Description = theme.Element( "description" ).Value,
                                           Author = theme.Element( "userName" ).Value,
                                           ThemeUrl = theme.Element( "url" ).Value,
                                           Id = Convert.ToInt32( theme.Element( "id" ).Value ),
                                           Rating = (int)Convert.ToDouble(theme.Element("numHearts").Value),
                                           Downloads = Convert.ToInt32(theme.Element("numViews").Value),
                                           CreatedAt = ToDate( theme.Element( "dateCreated" ).Value ),
                                           ColorList = from color in theme.Element( "colors" ).Elements( "hex" )
                                                       select ToColor( color.Value )
                                       };

                return query.ToList();
            }
        }

        private static Color ToColor(string hex)
        {
            return Color.FromArgb(255, 
                Convert.ToByte(hex.Substring(0, 2), 16), 
                Convert.ToByte(hex.Substring(2, 2), 16), 
                Convert.ToByte(hex.Substring(4, 2), 16));
        }

        public DateTime ToDate(string date)
        {
            return DateTime.ParseExact(date, "yyyy-MM-dd H:mm:ss", CultureInfo.InvariantCulture);            
        }

        private static string GetListName(ColorList list)
        {
            switch (list)
            {
                case ColorList.Popular:
                    return "top";
                case ColorList.Random:
                    return "random";
                case ColorList.None:
                case ColorList.Rating:
                case ColorList.Recent:
                default:
                    return "new";
            }
        }
    }
}
